package com.douqu.game.core.entity.ext;

import com.bean.core.buffer.ByteBuffer;
import com.douqu.game.core.config.MasterTrainConfig;
import com.douqu.game.core.config.common.CommonData;
import com.douqu.game.core.config.sprite.MasterConfig;
import com.douqu.game.core.entity.Player;
import com.douqu.game.core.entity.db.PropDB;
import com.douqu.game.core.entity.ext.data.boon.AutoRecover;
import com.douqu.game.core.factory.ConstantFactory;
import com.douqu.game.core.factory.DataFactory;
import com.douqu.game.core.factory.FunctionFactory;
import com.douqu.game.core.protobuf.SGCommonProto;
import com.douqu.game.core.util.CoreUtils;
import com.douqu.game.core.util.LogUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @author wangzhenfei
 * 2017-11-03 17:10
 * 玩家的设置信息
 */
public class SettingInfo extends ExtInfo {
    /**
     * 药水使用的改变值 <药水id， 数量>
     **/
    public Map<Integer, Integer> masterLiquidMap;
    /**
     * 消费不提醒 存储的是不需要提醒的id
     **/
    private List<Integer> consumeNotRemindList;
    private List<Integer> functionOpenIds;
    /**
     * 用户姓名更改次数
     **/
    private int playerNameChangeTimes;
    /**
     * 用户上阵技能
     **/
    private List<Integer> equipSkillIds;
    /**
     * 新解锁的技能id
     **/
    private int newUnlockSkillId;
    /**
     * 用户黑名单
     */
    private List<String> blackList;
    private String guideProgress;
    /**
     * 最后一次升级的时间
     */
    private long lastLvUpTime;
    /**
     * 主将的培养总属性 <属性id，提升值>
     **/
    private Map<Integer, Integer> masterAttributes;
    /**
     * 主将的培养上次的变更属性 <属性id，改变值>
     **/
    private Map<Integer, Integer> masterLastChangeAttributes;
    private AutoRecover autoRecover;

    public SettingInfo(Player player) {
        super(player);

        consumeNotRemindList = new CopyOnWriteArrayList<>();
        functionOpenIds = new CopyOnWriteArrayList<>();
        equipSkillIds = new CopyOnWriteArrayList<>();
        blackList = new CopyOnWriteArrayList<>();
        lastLvUpTime = DataFactory.currentTime;
        masterAttributes = new ConcurrentHashMap<>();
        masterLastChangeAttributes = new ConcurrentHashMap<>();
        masterLiquidMap = new ConcurrentHashMap<>();
        autoRecover = new AutoRecover();
    }

    @Override
    public void writeTo(ByteBuffer buffer) {
        buffer.writeByte(playerNameChangeTimes);
        int size = consumeNotRemindList.size();
        buffer.writeByte(size);
        for (int i = 0; i < size; i++) {
            buffer.writeShort(consumeNotRemindList.get(i));
        }
        size = equipSkillIds.size();
        if (size > 2) {
            try {
                throw new Exception("SettingInfo writeTo error equipSkillIds size > 2");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        buffer.writeByte(size);
        for (int i = 0; i < size; i++) {
            buffer.writeInt(equipSkillIds.get(i));
        }
        buffer.writeInt(newUnlockSkillId);
        size = blackList.size();
        buffer.writeByte(size);
        for (int i = 0; i < size; i++) {
            buffer.writeUTF(blackList.get(i));
        }
        buffer.writeUTF(guideProgress);
        buffer.writeLong(lastLvUpTime);

        buffer.writeShort(masterAttributes.size());
        for (Map.Entry<Integer, Integer> entry : masterAttributes.entrySet()) {
            buffer.writeInt(entry.getKey());
            buffer.writeInt(entry.getValue());
        }

        buffer.writeShort(masterLastChangeAttributes.size());
        for (Map.Entry<Integer, Integer> entry : masterLastChangeAttributes.entrySet()) {
            buffer.writeInt(entry.getKey());
            buffer.writeInt(entry.getValue());
        }

        buffer.writeShort(masterLiquidMap.size());
        for (Map.Entry<Integer, Integer> entry : masterLiquidMap.entrySet()) {
            buffer.writeInt(entry.getKey());
            buffer.writeInt(entry.getValue());
        }

        buffer.writeBoolean(true);
        //++++++++++++++++++++++++++++++++++++++++++++
        size = functionOpenIds.size();
        buffer.writeByte(size);
        for (int i = 0; i < size; i++) {
            buffer.writeShort(functionOpenIds.get(i));
        }
        buffer.writeBoolean(false);

        buffer.writeBoolean(autoRecover.enable);
        buffer.writeInt(autoRecover.maxUseTimes);
        buffer.writeInt(autoRecover.percent);

        buffer.writeInt(autoRecover.autoUseTimes);
        buffer.writeByte(autoRecover.getUseTimes().size());
        for (Map.Entry<Integer,Integer> e: autoRecover.getUseTimes().entrySet()) {
            buffer.writeInt(e.getKey());
            buffer.writeInt(e.getValue());
        }

        autoRecover.writeTo(buffer);
    }


    @Override
    public void loadFrom(ByteBuffer buffer) {

        playerNameChangeTimes = buffer.readByte();
        int size = buffer.readByte();
        for (int i = 0; i < size; i++) {
            consumeNotRemindList.add(buffer.readShort());
        }
        size = buffer.readByte();
        if (size > 2) {
            try {
                throw new Exception("SettingInfo loadFrom error equipSkillIds size > 2");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        int skillId = 0;
        for (int i = 0; i < size; i++) {
            skillId = buffer.readInt();
            if (DataFactory.getInstance().getGameObject(DataFactory.SKILL_KEY, skillId) == null) {
                try {
                    throw new Exception("SettingInfo loadFrom error equipSkillId :" + skillId);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            equipSkillIds.add(skillId);
        }
        newUnlockSkillId = buffer.readInt();
        size = buffer.readByte();
        for (int i = 0; i < size; i++) {
            blackList.add(buffer.readUTF());
        }
        guideProgress = buffer.readUTF();
        lastLvUpTime = buffer.readLong();

        size = buffer.readShort();
        for (int i = 0; i < size; i++) {
            masterAttributes.put(buffer.readInt(), buffer.readInt());
        }

        size = buffer.readShort();
        for (int i = 0; i < size; i++) {
            masterLastChangeAttributes.put(buffer.readInt(), buffer.readInt());
        }

        size = buffer.readShort();
        for (int i = 0; i < size; i++) {
            masterLiquidMap.put(buffer.readInt(), buffer.readInt());
        }

        boolean flag = buffer.readBoolean();
        if (flag) {
            size = buffer.readByte();
            for (int i = 0; i < size; i++) {
                functionOpenIds.add(buffer.readShort());
            }
            buffer.readBoolean();
        }
        autoRecover.enable = buffer.readBoolean();
        autoRecover.maxUseTimes = buffer.readInt();
        autoRecover.percent = buffer.readInt();

        autoRecover.autoUseTimes = buffer.readInt();
        size = buffer.readByte();
        for (int i = 0; i < size; i++) {
            autoRecover.getUseTimes().put(buffer.readInt(),buffer.readInt());
        }

        //+++++++++++++++++++++++++++++++新加的
        autoRecover.loadForm(buffer);
        //+++++++++++++++++++++++++++++++
    }


    @Override
    public List<SGCommonProto.E_RED_POINT_TYPE> checkRedPointRemindAllCondition(long currentTime) {
//        if(hasNewUnlockSkill()){
        if (hasUseLiquid()) {
            List<SGCommonProto.E_RED_POINT_TYPE> list = new ArrayList<>();
            list.add(SGCommonProto.E_RED_POINT_TYPE.RED_POINT_TYPE_MASTER);
            return list;
        }
        return super.checkRedPointRemindAllCondition(currentTime);

    }

    /**
     * 是否有可用的药水
     *
     * @return
     */
    private boolean hasUseLiquid() {
        if (!CoreUtils.isFunctionUnLock(FunctionFactory.FUNCTION_USE_LIQUID, player)) {
            return false;
        }
        BagInfo bagInfo = player.getExtInfo(BagInfo.class);
        List<PropDB> propDBs = bagInfo.getPropTypeMap().get(ConstantFactory.PROP_TYPE_LIQUID);
        if (propDBs != null) {
            for (PropDB propDB : propDBs) {
                if (!isUseLiquidTouchMax(propDB.id, 1)) {
                    return true;
                }
            }
        }
        return false;
    }

    public void addPlayerNameChangeTimes() {
        playerNameChangeTimes++;
        if (playerNameChangeTimes > Byte.MAX_VALUE) {
            playerNameChangeTimes = 10;
        }
    }

    /**
     * 改变上阵技能
     */
    public void changeEquipSkill(List<Integer> ids) {
        equipSkillIds.clear();
        for (Integer id : ids) {
            equipSkillIds.add(id);
        }
    }

    /**
     * 升级的时候添加默认上阵技能
     */
    public void levelUpToAddDefaultSkill() {
        int equipSkillSize = equipSkillIds.size();
        if (equipSkillSize < 2) { //只有0和1技能
            MasterConfig masterConfig = DataFactory.getInstance().getGameObject(DataFactory.MASTER_KEY, player.master);
            if (masterConfig == null) {
                LogUtils.error("SettingInfo checkInit() master 找不到 master：" + player.master);
                try {
                    throw new Exception(" 找不到 master");
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return;
            }
            for (CommonData data : masterConfig.skills) {
                if (equipSkillIds.size() >= 2 || player.getLv() < data.id) {//自己的等级小于配置的要求的最低等级
                    break;
                }
                if (!equipSkillIds.contains(Integer.valueOf(data.value))) {
                    equipSkillIds.add(data.value);
                }
            }
        }
    }


    /**
     * @param beforeLevel
     */
    public boolean levelUpToNewUnlockSkill(int beforeLevel) {
        levelUpToAddDefaultSkill();
        int nowLevel = player.getLv();
        MasterConfig masterConfig = DataFactory.getInstance().getGameObject(DataFactory.MASTER_KEY, player.master);
        if (masterConfig == null) {
            LogUtils.error("SettingInfo checkInit() master 找不到 master：" + player.master);
            return false;
        }
        for (CommonData data : masterConfig.skills) {
            if (data.id > beforeLevel && data.id <= nowLevel) {//有新的技能解锁了
                newUnlockSkillId = data.value;
//               LogUtils.debug("SettingInfo 有新的技能解锁了id为：" + newUnlockSkillId);
                return true;
            }
        }

        return false;
    }

    /***
     * 加入黑名单
     * @param accountIndex
     */
    public void addBlackList(String accountIndex) {
        blackList.add(accountIndex);
    }

    /***
     * 移除黑名单
     * @param accountIndex
     */
    public void removeBlackList(String accountIndex) {
        blackList.remove(accountIndex);
    }


    /***
     * 检测是否在黑明单存在
     * @param accountIndex
     * @return
     */
    public boolean isContains(String accountIndex) {
        if (blackList != null && blackList.size() > 0) {
            if (blackList.contains(accountIndex))
                return true;
            else
                return false;
        } else {
            return false;
        }

    }


    public boolean isFirstChangeName() {
        return playerNameChangeTimes == 0;
    }


    public List<Integer> getConsumeNotRemindList() {
        return consumeNotRemindList == null ? consumeNotRemindList = new CopyOnWriteArrayList<>() : consumeNotRemindList;
    }

    public List<Integer> getFunctionOpenIds() {
        return functionOpenIds == null ? functionOpenIds = new CopyOnWriteArrayList<>() : functionOpenIds;
    }


    public List<Integer> getEquipSkillIds() {
        return equipSkillIds == null ? equipSkillIds = new CopyOnWriteArrayList<>() : equipSkillIds;
    }

    public int getPlayerNameChangeTimes() {
        return playerNameChangeTimes;
    }

    public void removeNewUnlockSkill() {
        newUnlockSkillId = 0;
    }

    public boolean hasNewUnlockSkill() {
        return newUnlockSkillId != 0;
    }

    public int getNewUnlockSkillId() {
        return newUnlockSkillId;
    }

    public String getGuideProgress() {
        return guideProgress == null ? "" : guideProgress;
    }

    public void setGuideProgress(String guideProgress) {
        this.guideProgress = guideProgress;
    }

    public Map<Integer, Integer> getMasterAttributes() {
        return masterAttributes;
    }

    public List<SGCommonProto.CommonObject> getResponseMasterAttributes() {
        List<SGCommonProto.CommonObject> list = new ArrayList<>();
        for (Map.Entry<Integer, Integer> entry : masterAttributes.entrySet()) {
            list.add(SGCommonProto.CommonObject.newBuilder().setId(entry.getKey()).setValue(entry.getValue()).build());
        }
        return list;
    }

    public Map<Integer, Integer> getMasterLastChangeAttributes() {
        return masterLastChangeAttributes;
    }

    public List<SGCommonProto.CommonObject> getResponseMasterLastChangeAttributes() {
        List<SGCommonProto.CommonObject> list = new ArrayList<>();
        for (Map.Entry<Integer, Integer> entry : masterLastChangeAttributes.entrySet()) {
            list.add(SGCommonProto.CommonObject.newBuilder().setId(entry.getKey()).setValue(entry.getValue()).build());
        }
        return list;
    }

    @Override
    public void init() {
        levelUpToAddDefaultSkill();
        checkMasterTrain();
    }

    @Override
    public void checkInit() {
        levelUpToAddDefaultSkill();
        if (DataFactory.getInstance().getDataList(DataFactory.MASTER_TRAIN_KEY).size() != masterAttributes.size()) {
            //属性初始化
            checkMasterTrain();
        }
    }

    private void checkMasterTrain() {
        List<MasterTrainConfig> configs = DataFactory.getInstance().getDataList(DataFactory.MASTER_TRAIN_KEY);
        for (MasterTrainConfig config : configs) {
            if (masterAttributes.get(config.getId()) == null) {
                masterAttributes.put(config.id, 0);
            }
        }
    }

    /***************************************药水****************************************/
    /**
     * 获取药水使用量
     *
     * @param propId
     * @return
     */
    public int getUseLiquidCount(int propId) {
        Integer count = masterLiquidMap.get(propId);
        return count == null ? 0 : count.intValue();
    }

    /**
     * 增加药水使用量
     *
     * @param propId
     * @param count
     * @return
     */
    public int addLiquidUseCount(int propId, int count) {
        Integer totalCount = masterLiquidMap.get(propId);
        totalCount = (totalCount == null ? 0 : totalCount.intValue()) + count;
        masterLiquidMap.put(propId, totalCount);
        return totalCount;
    }

    /**
     * 药水使用是否达到了最大值
     *
     * @param propId
     * @param count
     * @return
     */
    public boolean isUseLiquidTouchMax(int propId, int count) {
        int totalCount = getUseLiquidCount(propId);
        totalCount += count;
        Integer max = player.getPlayerLvConfig().useLiquidMaxCount.get(propId);
        max = max == null ? 0 : max.intValue();
        if (totalCount > max) {
            LogUtils.debug("药水使用达到最大值, max = " + max + ", targetCount = " + totalCount);
            return true;
        }
        return false;
    }

    /**
     * 获取吃药的prop
     *
     * @return
     */
    public List<SGCommonProto.CommonObject> getUseLiquidProp() {
        List<SGCommonProto.CommonObject> list = new ArrayList<>();
        for (Map.Entry<Integer, Integer> entry : masterLiquidMap.entrySet()) {
            list.add(SGCommonProto.CommonObject.newBuilder().setId(entry.getKey()).setValue(entry.getValue()).build());
        }
        return list;
    }

    public Map<Integer, Integer> getMasterLiquidMap() {
        return masterLiquidMap;
    }

    @Override
    public void reset() {

    }

    @Override
    public void checkReset() {

    }

    public List<String> getBlackList() {
        return blackList;
    }

    public void setBlackList(List<String> blackList) {
        this.blackList = blackList;
    }

    public long getLastLvUpTime() {
        return lastLvUpTime;
    }

    public void setLastLvUpTime(long lastLvUpTime) {
        this.lastLvUpTime = lastLvUpTime;
    }

    public void addFunctionOpenId(int functionId) {
        if (!getFunctionOpenIds().contains(functionId)) {
            getFunctionOpenIds().add(functionId);
        }
    }

    public AutoRecover getAutoRecover() {
        return autoRecover;
    }
}
